/*
 *                  BioJava development code
 *
 * This code may be freely distributed and modified under the
 * terms of the GNU Lesser General Public Licence.  This should
 * be distributed with the code.  If you do not have a copy,
 * see:
 *
 *      http://www.gnu.org/copyleft/lesser.html
 *
 * Copyright for this code is held jointly by the individual
 * authors.  These should be listed in @author doc comments.
 *
 * For more information on the BioJava project and its aims,
 * or to join the biojava-l mailing list, visit the home page
 * at:
 *
 *      http://www.biojava.org/
 * 
 * Created on Mar 20, 2007
 * 
 */

package dasregistry;

import java.net.MalformedURLException;
import java.net.URL;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;

import org.biojava.dasobert.das.Capabilities;
import org.biojava.dasobert.dasregistry.DasCoordinateSystem;
import org.biojava.dasobert.dasregistry.DasSource;
import org.biojava.services.das.dao.DasSourceManager;
import org.biojava.services.das.registry.AutoActivation;
import org.biojava.services.das.registry.DasClient;
import org.biojava.services.das.registry.DasCoordinateSystemCollector;
import org.biojava.services.das.registry.DasRegistrySql;
import org.biojava.services.das.registry.RegistryConfiguration;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;



public class ActivationURLCreator {

	private static final String ENSEMBL_LABEL = "ENSEMBL";
	private static final int ENSEMBL_CLIENT_ID = 1;

	public static final int CREATION_OK = 0;
	public static final int CREATION_FAILED = -1;
	public static final int NOT_A_URL = 33;
	
	// get from config file!
	private static final String DEFAUT_PREFIX = "DS";
	
	
	private  String DATASOURCE_NAME ;


	protected DataSource dataSource ;  

	DasSourceManager dasSourceManager;
	DasClient[] configClients;

	public static DasClient[] CONFIG_DAS_CLIENTS;
	public static AutoActivation[] CONFIG_AUTO_ACTIVATION;
	static {

		RegistryConfiguration rconfig = new RegistryConfiguration();
		Map configuration = rconfig.getConfiguration();
		CONFIG_DAS_CLIENTS = (DasClient[]) configuration.get("DASClients");
		CONFIG_AUTO_ACTIVATION = (AutoActivation[]) configuration.get("AutoActivation");
	}

	public ActivationURLCreator() {

		//System.out.println("ActivationURLCreator init");
		DATASOURCE_NAME = DasRegistrySql.DATASOURCE_NAME;
		try {
			Context env = (Context) new InitialContext().lookup("java:comp/env");
			dataSource = (DataSource) env.lookup(DATASOURCE_NAME);
		} catch ( Exception e) {
			e.printStackTrace();
		}   
		BeanFactory ctx=(new ClassPathXmlApplicationContext("SpringDAO.xml"));
		dasSourceManager=(DasSourceManager) ctx.getBean("dasSourceManager");
		


	}

	
	
	public int removeActivationUrl(String url, String activationUrl){
		int status = CREATION_OK;
		
		Connection conn = null;
		
		try {
			conn = dataSource.getConnection() ;
			
			int auto_id = dasSourceManager.getAutoIdForURL(url);
			
			dasSourceManager.removeAutoActivation(conn, auto_id, activationUrl);
		} catch ( SQLException e) {			
			e.printStackTrace();
			status = CREATION_FAILED;
		} finally {
			if ( conn != null ) {
				try {
					conn.close();
				} catch ( SQLException ex) {
					ex.printStackTrace();
					status = CREATION_FAILED;
				}
			}
		}
		
		return status;
	}
	
	
	/** create a new auto activation url for a DAS source
	 * 
	 * @param url the url of the DAS source
	 * @param clientName 
	 * @param activationUrl 
	 * @param coordSys 
	 * @return a status (CREATION_OK, FAILED or NOT A URL)
	 */
	public int createAutoURL(String url,
			String clientName,
			String activationUrl , 
			String coordSys){
		
		int status = CREATION_OK;
		
		System.out.println("creating new auto-url " + activationUrl);
						
		try {
			 new URL(activationUrl);
		} catch (MalformedURLException e){
			return NOT_A_URL;
		}
		
		Connection conn = null;
		
		try {
			conn = dataSource.getConnection() ;
			
			DasCoordinateSystemCollector coordmap = dasSourceManager.getAllCoordinateSystemsMap(conn, DEFAUT_PREFIX );
			
			Integer coordNS_auto = coordmap.getCoordinateSystemID(coordSys);
									
			DasCoordinateSystem dcs = coordmap.get(coordNS_auto);
			
			AutoActivation aa =new AutoActivation();
			aa.setCoordSys(dcs);
			aa.setActivationURL(activationUrl);
			
			// get DAS client
			DasClient client = getClient(clientName);
			
			aa.setClient(client);
							
			dasSourceManager.createAutoActivation(conn, aa , coordNS_auto.intValue(), url);
			
			
		} catch ( SQLException e) {			
			e.printStackTrace();
			status = CREATION_FAILED;
		} finally {
			if ( conn != null ) {
				try {
					conn.close();
				} catch ( SQLException ex) {
					ex.printStackTrace();
					status = CREATION_FAILED;
				}
			}
		}
		return status;
			
	}
	
	public DasClient getClient(String clientName){
		for (int i=0 ; i < CONFIG_DAS_CLIENTS.length ; i++ ){
			DasClient c = CONFIG_DAS_CLIENTS[i];
			if ( c.getName().equalsIgnoreCase(clientName))
				return c;
		}
		return null;
	}
	
	
	
	public AutoActivation[] getNotEditableConfigURLs(String url){
		Connection conn = null;

		AutoActivation[] allaa = new AutoActivation[0];

		try {
			conn = dataSource.getConnection() ;

			int auto_id = dasSourceManager.getAutoIdForURL(url);
			
			DasSource ds = dasSourceManager.getDasSourceById(conn, auto_id);
				
			AutoActivation[] aa1 = new AutoActivation[0];
			//AutoActivation[] aa1 = getAutoActivationURLs(conn,ds,auto_id);
			AutoActivation[] aa2 = getDefaultEnsemblActivationURLs(conn,ds);
			AutoActivation[] aa3 = getConfigActivationUrls(ds);
			
			allaa = new AutoActivation[aa1.length + aa2.length + aa3.length];
			System.arraycopy(aa1, 0, allaa, 0, aa1.length);
			System.arraycopy(aa2,0,allaa,aa1.length,aa2.length);
			System.arraycopy(aa3,0,allaa,(aa1.length+aa2.length),aa3.length);

		} catch ( SQLException e) {			
			e.printStackTrace();
		} finally {
			if ( conn != null ) {
				try {
					conn.close();
				} catch ( SQLException ex) {
					ex.printStackTrace();
				}
			}
		}

		return allaa;		
	}	
	
	
	public AutoActivation[] getAllActivationURLs(String url){
		Connection conn = null;

		AutoActivation[] allaa = new AutoActivation[0];

		try {
			conn = dataSource.getConnection() ;

			int auto_id = dasSourceManager.getAutoIdForURL(url);
			
			DasSource ds = dasSourceManager.getDasSourceById(conn, auto_id);
				
			//AutoActivation[] aa1 = new AutoActivation[0];
			AutoActivation[] aa1 = getAutoActivationURLs(conn,ds,auto_id);
			AutoActivation[] aa2 = getDefaultEnsemblActivationURLs(conn,ds);
			AutoActivation[] aa3 = getConfigActivationUrls(ds);
			
			////System.out.println(" got " + aa1.length + " " + aa2.length + " " + aa3.length);
			
			allaa = new AutoActivation[aa1.length + aa2.length + aa3.length];
			System.arraycopy(aa1, 0, allaa, 0, aa1.length);
			System.arraycopy(aa2,0,allaa,aa1.length,aa2.length);
			System.arraycopy(aa3,0,allaa,(aa1.length+aa2.length),aa3.length);

		} catch ( SQLException e) {			
			e.printStackTrace();
		} finally {
			if ( conn != null ) {
				try {
					conn.close();
				} catch ( SQLException ex) {
					ex.printStackTrace();
				}
			}
		}

		return allaa;		
	}



	private AutoActivation[] getConfigActivationUrls(DasSource ds){

		// alignment DAS sources currently can not be activated
		if ( ds.hasCapability(Capabilities.ALIGNMENT.getCommand())){
			return new AutoActivation[0];
		}

		//if (  hasEnsemblLabel(ds.getLabels()))
		//	return new AutoActivation[0];
		
		
		DasCoordinateSystem[] css = ds.getCoordinateSystem();
		
		List data = new ArrayList();
		for (int i=0 ; i< css.length ; i++){
			DasCoordinateSystem cs = css[i];
			
			for (int a = 0 ; a< CONFIG_AUTO_ACTIVATION.length; a++) {
				AutoActivation aa = CONFIG_AUTO_ACTIVATION[a];
				if ( aa.getCoordSys().toString().equals(cs.toString())){
					//System.out.println(aa.getCoordSys().toString() + " ==" + cs.toString());
					// just to be sure there are testcodes in this coordsys
					aa.setCoordSys(cs);
					data.add(aa);
				}
			}
		}
		return (AutoActivation[]) data.toArray(new AutoActivation[data.size()]);
	}


	public AutoActivation[] getUserConfigAutoActivation(String url){
		Connection conn = null;

		AutoActivation[] allaa = new AutoActivation[0];

		try {
			conn = dataSource.getConnection() ;
			
			int auto_id = dasSourceManager.getAutoIdForURL(url);
			
			DasSource ds = dasSourceManager.getDasSourceById(conn, auto_id);
			
			allaa = getAutoActivationURLs(conn,ds,auto_id);
			
		} catch ( SQLException e) {			
	
			e.printStackTrace();
	
		} finally {
		
			if ( conn != null ) {
				try {
					conn.close();
				} catch ( SQLException ex) {
					ex.printStackTrace();
				}
			}
			
		}
		
		return allaa;

	}
	
	
	public AutoActivation[] getAutoActivationURLs(Connection conn, DasSource ds, int auto_id) 
	throws SQLException{

		AutoActivation[] activation = new AutoActivation[0];
	
		activation = dasSourceManager.getAutoActivation(conn,ds,auto_id);

		return activation;		
	}

	private static boolean hasEnsemblLabel(String[] labels ){
		boolean hasEnsemblLabel = false;

		for ( int i = 0 ; i< labels.length ;i++){
			String lab = labels[i];
			if ( lab.equals(ENSEMBL_LABEL)){
				hasEnsemblLabel = true;
				break;
			}
		}
		return hasEnsemblLabel;
	}



	private  AutoActivation[] getDefaultEnsemblActivationURLs(Connection conn, DasSource ds) 
	throws SQLException {
		List data = new ArrayList();
		
		if ( ! hasEnsemblLabel(ds.getLabels()))
			return new AutoActivation[0];
		
		DasClient ensembl = dasSourceManager.getDasClient(conn, ENSEMBL_CLIENT_ID);

		DasCoordinateSystem[] coordSys = ds.getCoordinateSystem();
		for ( int i = 0 ; i< coordSys.length ; i++){
			DasCoordinateSystem cs = coordSys[i];

			// this only works with Chromosomal coordinate systems ...		
			String type ="+type=";
			if (  cs.getCategory().equals("Chromosome"))
				type += "ensembl_location_chromosome";
			else if ( cs.getCategory().equals("Clone"))
				type += "ensembl_location_clone";
			
			else {
				// this type is not supported (yet)!
				continue;
			}

			String assemblyString = cs.getName() + cs.getVersion();
			
			String activationString = "http://www.ensembl.org/";
			activationString += cs.getOrganismName().replaceAll(" ", "_");
//			activationString+= "/contigview?region=%reference&amp;" +
//			"vc_start=%start&amp;vc_end=%stop&amp;"+
//			"add_das_source=(url=%ensurl+dsn=%dsn"+type+"+name=%nickname+assembly="+
//			assemblyString +"+group=N+active=1)";
			
			
			//new version of activation string for ensembl as of 4 June 2009
			activationString+="/Location/View?r=%reference"+
			":%start-%stop"+
			";contigviewbottom=das:http://www.dasregistry.org/das/sources/"+ds.getId().replace("null", "DS")+"=label";
			//http://www.ensembl.org/Mus_musculus/contigview?region=1&vc_start=174405453&vc_end=174408689&add_das_source=(url=http://das.sanger.ac.uk/das+dsn=ccds_mouse+type=ensembl_location_chromosome+name=CCDS_mouse+assembly=NCBIM37+group=N+active=1)
			//http://www.ensembl.org/Mus_musculus/Location/View?r=1:174405453-174408689;contigviewbottom=das:http://www.dasregistry.org/das/sources/DS_555=label
			

			AutoActivation aa = new AutoActivation();
			aa.setClient(ensembl);
			aa.setCoordSys(cs);
			aa.setActivationURL(activationString);
			//System.out.println(aa);
			data.add(aa);

		}

		return (AutoActivation[])data.toArray(new AutoActivation[data.size()]);	
	}





}
